/*
 * NyuArray.cpp
 *
 *  Created on: 2010/05/29
 *      Author: mitsu
 */

#include <iostream>
#include "NyuArray.hpp"
#include "NyuGC.hpp"

NyuArray::NyuArray(NyuObject* proto) : NyuObject(proto) {
}

NyuArray::NyuArray(NyuObject* proto, size_t size) :
        NyuObject(proto), data_(size) {
}

NyuArray::~NyuArray() {
}

NyuValue NyuArray::getitem(NyuValue idx, NyuContext* c) {
    switch (NYU_VALUE_TAG(idx)) {
    case NYU_VALUE_TAG_INT:
        {
            std::deque<NyuValue>::size_type i = NYU_VALUE_TO_INT(idx);
            if (i < 0 || data_.size() <= i)
                return 0;
            return data_[i];
        }
        break;

    case NYU_VALUE_TAG_NATIVE:
        std::cerr << "Sorry! currently cannot use Native for index." << std::endl;
        break;

    case NYU_VALUE_TAG_OBJECT:
        return getSlot(NYU_VALUE_UNTAG_OBJECT(idx), c);

    case NYU_VALUE_TAG_BLOCK:
        std::cerr << "Sorry! currently cannot use Block for index." << std::endl;
        break;
    }

    return 0;
}

void NyuArray::putitem(NyuValue idx, NyuValue val, NyuContext* c) {
    switch (NYU_VALUE_TAG(idx)) {
    case NYU_VALUE_TAG_INT:
        {
            std::deque<NyuValue>::size_type i = NYU_VALUE_TO_INT(idx);
            if (i < 0) {
            } else if (data_.size() <= i) {
                data_.resize(i);
                data_[i] = val;
            } else {
                data_[i] = val;
            }
        }
        break;

    case NYU_VALUE_TAG_NATIVE:
        std::cerr << "Sorry! currently cannot use Native for index." << std::endl;
        break;

    case NYU_VALUE_TAG_OBJECT:
        putSlot(NYU_VALUE_UNTAG_OBJECT(idx), val, c);
        break;

    case NYU_VALUE_TAG_BLOCK:
        std::cerr << "Sorry! currently cannot use Block for index." << std::endl;
        break;
    }
}

NyuValue NyuArray::getLength(NyuContext* c) {
    return NYU_INT_TO_VALUE(data_.size());
}

NyuValue NyuArray::push(NyuContext* c) {
    for (int i = 1, j = c->current_argc(); i < j; i++) {
        NyuValue val = c->current_argv(i);
        data_.push_back(val);
    }
    return 0;
}

NyuValue NyuArray::pop(NyuContext* c) {
    if (data_.empty())
        return 0;

    NyuValue val = data_.back();
    data_.pop_back();
    return val;
}

void NyuArray::copyChildren(bool* has_new_obj) {
    NyuObject::copyChildren(has_new_obj);

    for (std::deque<NyuValue>::iterator it = data_.begin(), end = data_.end();
            it != end; ++it) {
        NyuValue val = *it;

        if (!NYU_VALUE_IS_OBJECT(val))
            continue;

        NyuObject* obj = NYU_VALUE_UNTAG_OBJECT(val);
        (*it) = NYU_OBJECT_TO_VALUE(NyuGC::copy(obj, has_new_obj));
    }
}

NyuValue NyuArray::each_func(NyuContext* c) {
    return 0;
}

NyuValue NyuArray::length_func(NyuContext* c) {
    NyuValue target = c->getCurrentTarget();
    if (!NYU_VALUE_IS_OBJECT(target))
        return 0;
    return NYU_VALUE_UNTAG_OBJECT(target)->getLength(c);
}

NyuValue NyuArray::push_func(NyuContext* c) {
    NyuValue target = c->getCurrentTarget();
    if (!NYU_VALUE_IS_OBJECT(target))
        return 0;
    return NYU_VALUE_UNTAG_OBJECT(target)->push(c);
}

NyuValue NyuArray::pop_func(NyuContext* c) {
    NyuValue target = c->getCurrentTarget();
    if (!NYU_VALUE_IS_OBJECT(target))
        return 0;
    return NYU_VALUE_UNTAG_OBJECT(target)->pop(c);
}
